//
//  ZoomingScrollView.m
//  EJPhotoBrowser
//
//  Created by Michael Waterfall on 14/10/2010.
//  Copyright 2010 d3i. All rights reserved.
//

#import <DACircularProgress/DACircularProgressView.h>
#import "EJZoomingScrollView.h"
#import "EJPhotoBrowser.h"
#import "EJPhotoBrowserPrivate.h"
#import "UIImage+EJPhotoBrowser.h"

@interface EJZoomingScrollView () {
    
    EJPhotoBrowser __weak *_photoBrowser;
    EJTapDetectingView *_tapView; // for background taps
    EJTapDetectingImageView *_photoImageView;
    DACircularProgressView *_loadingIndicator;
}

@end

@implementation EJZoomingScrollView

- (id)initWithPhotoBrowser:(EJPhotoBrowser *)browser {
    if ((self = [super init])) {
        
        if (@available(iOS 11.0, *)) {
            self.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
        }
        
        // Setup
        _index = NSUIntegerMax;
        _photoBrowser = browser;
        
        // Tap view for background
        _tapView = [[EJTapDetectingView alloc] initWithFrame:self.bounds];
        _tapView.tapDelegate = self;
        _tapView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
        _tapView.backgroundColor = [UIColor blackColor];
        [self addSubview:_tapView];
        
        // Image view
        _photoImageView = [[EJTapDetectingImageView alloc] initWithFrame:CGRectZero];
        _photoImageView.tapDelegate = self;
        _photoImageView.contentMode = UIViewContentModeScaleAspectFill;
        _photoImageView.backgroundColor = [UIColor blackColor];
        [self addSubview:_photoImageView];
        
        // Loading indicator
        _loadingIndicator = [[DACircularProgressView alloc] initWithFrame:CGRectMake(140.0f, 30.0f, 40.0f, 40.0f)];
        _loadingIndicator.userInteractionEnabled = NO;
        _loadingIndicator.thicknessRatio = 0.1;
        _loadingIndicator.roundedCorners = NO;
        _loadingIndicator.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleTopMargin |
        UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleRightMargin;
        [self addSubview:_loadingIndicator];

        // Listen progress notifications
        [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(setProgressFromNotification:)
                                                     name:EJPHOTO_PROGRESS_NOTIFICATION
                                                   object:nil];
        
        // Setup
        self.backgroundColor = [UIColor blackColor];
        self.delegate = self;
        self.showsHorizontalScrollIndicator = NO;
        self.showsVerticalScrollIndicator = NO;
        self.decelerationRate = UIScrollViewDecelerationRateFast;
        self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
        self.minimumZoomScale = 1;
        self.scrollsToTop = NO;
        self.bouncesZoom = YES;
        self.delaysContentTouches = NO;
        self.canCancelContentTouches = YES;
        self.alwaysBounceVertical = NO;
        
    }
    return self;
}

- (void)dealloc {
    if ([_photo respondsToSelector:@selector(cancelAnyLoading)]) {
        [_photo cancelAnyLoading];
    }
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

- (void)prepareForReuse {
    [self hideImageFailure];
    self.photo = nil;
//    self.captionView = nil;
//    self.selectedButton = nil;
    self.playButton = nil;
    _photoImageView.hidden = NO;
    _photoImageView.image = nil;
    _index = NSUIntegerMax;
}

- (BOOL)displayingVideo {
    return [_photo respondsToSelector:@selector(isVideo)] && _photo.isVideo;
}

- (void)setImageHidden:(BOOL)hidden {
    _photoImageView.hidden = hidden;
}

#pragma mark - Image
- (void)configPhoto:(id<EJPhoto>)photo thumb:(id<EJPhoto>)thumb {
    if (_photo && photo == nil) {
        if ([_photo respondsToSelector:@selector(cancelAnyLoading)]) {
            [_photo cancelAnyLoading];
        }
    }
    _photo = photo;
    _thumb = thumb;
    UIImage * img;
    if (_photo.isVideo == NO) {// 不是视频
        img = [_photoBrowser imageForPhoto:_photo];
    } else {// 视频
        EJPhoto * item = (EJPhoto *)_photo;
        if ([item.videoURL.absoluteString length] > 0) {// 网络视频
            img = [_photoBrowser imageForPhoto:_thumb];
        } else {
            img = [_photoBrowser imageForPhoto:_photo];
        }
    }
    if (img) {
        [self displayImage];
    } else {
        // Will be loading so show loading
        [self showLoadingIndicator];
    }
}

//- (void)setPhoto:(id<EJPhoto>)photo {
//    // Cancel any loading on old photo
//    if (_photo && photo == nil) {
//        if ([_photo respondsToSelector:@selector(cancelAnyLoading)]) {
//            [_photo cancelAnyLoading];
//        }
//    }
//    _photo = photo;
//    UIImage *img = [_photoBrowser imageForPhoto:_photo];
//    if (img) {
//        [self displayImage];
//    } else {
//        // Will be loading so show loading
//        [self showLoadingIndicator];
//    }
//}

// Get and display image
- (void)displayImage {
    if ((_photo || _thumb) && _photoImageView.image == nil) {
        
        // Reset
        self.maximumZoomScale = 1;
        self.minimumZoomScale = 1;
        self.zoomScale = 1;
        self.contentSize = CGSizeMake(0, 0);
        
        // Get image from browser as it handles ordering of fetching
//        UIImage *img = [_photoBrowser imageForPhoto:_photo];
        UIImage * img;
        if (_photo.isVideo == NO) {// 不是视频
            img = [_photoBrowser imageForPhoto:_photo];
        } else {// 视频
            EJPhoto * item = (EJPhoto *)_photo;
            if ([item.videoURL.absoluteString length] > 0) {// 网络视频
                img = [_photoBrowser imageForPhoto:_thumb];
            } else {
                img = [_photoBrowser imageForPhoto:_photo];
            }
        }
        if (img) {
            
            // Hide indicator
            [self hideLoadingIndicator];
            
            // Set image
            _photoImageView.image = img;
            _photoImageView.hidden = NO;
            
            // Setup photo frame
            CGRect photoImageViewFrame;
            photoImageViewFrame.origin = CGPointZero;
            photoImageViewFrame.size = img.size;
            _photoImageView.frame = photoImageViewFrame;
            self.contentSize = photoImageViewFrame.size;

            // Set zoom to minimum zoom
            [self setMaxMinZoomScalesForCurrentBounds];
            
        } else  {

            // Show image failure
            [self displayImageFailure];
            
        }
        [self setNeedsLayout];
    }
}

// Image failed so just show black!
- (void)displayImageFailure {
    [self hideLoadingIndicator];
    _photoImageView.image = nil;
    
    // Show if image is not empty
    if (![_photo respondsToSelector:@selector(emptyImage)] || !_photo.emptyImage) {
//        if (!_loadingError) {
//            _loadingError = [UIImageView new];
//            _loadingError.image = [UIImage imageForResourcePath:@"EJPhotoBrowser.bundle/ImageError" ofType:@"png" inBundle:[NSBundle bundleForClass:[self class]]];
//            _loadingError.userInteractionEnabled = NO;
//            _loadingError.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleTopMargin |
//            UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleRightMargin;
//            [_loadingError sizeToFit];
//            [self addSubview:_loadingError];
//        }
//        _loadingError.frame = CGRectMake(floorf((self.bounds.size.width - _loadingError.frame.size.width) / 2.), floorf((self.bounds.size.height - _loadingError.frame.size.height) / 2), _loadingError.frame.size.width, _loadingError.frame.size.height);
    }
}

- (void)hideImageFailure {
//    if (_loadingError) {
//        [_loadingError removeFromSuperview];
//        _loadingError = nil;
//    }
}

#pragma mark - Loading Progress

- (void)setProgressFromNotification:(NSNotification *)notification {
    dispatch_async(dispatch_get_main_queue(), ^{
        NSDictionary *dict = [notification object];
        id <EJPhoto> photoWithProgress = [dict objectForKey:@"photo"];
        if (photoWithProgress == self.photo) {
            float progress = [[dict valueForKey:@"progress"] floatValue];
            _loadingIndicator.progress = MAX(MIN(1, progress), 0);
        }
    });
}

- (void)hideLoadingIndicator {
    _loadingIndicator.hidden = YES;
}

- (void)showLoadingIndicator {
    self.zoomScale = 0;
    self.minimumZoomScale = 0;
    self.maximumZoomScale = 0;
    _loadingIndicator.progress = 0;
    _loadingIndicator.hidden = NO;
    [self hideImageFailure];
}

#pragma mark - Setup

//- (CGFloat)initialZoomScaleWithMinScale {
//    CGFloat zoomScale = self.minimumZoomScale;
//    if (_photoImageView && _photoBrowser.zoomPhotosToFill) {
//        // Zoom image to fill if the aspect ratios are fairly similar
//        CGSize boundsSize = self.bounds.size;
//        CGSize imageSize = _photoImageView.image.size;
//        CGFloat boundsAR = boundsSize.width / boundsSize.height;
//        CGFloat imageAR = imageSize.width / imageSize.height;
//        CGFloat xScale = boundsSize.width / imageSize.width;    // the scale needed to perfectly fit the image width-wise
//        CGFloat yScale = boundsSize.height / imageSize.height;  // the scale needed to perfectly fit the image height-wise
//        // Zooms standard portrait images on a 3.5in screen but not on a 4in screen.
//        if (ABS(boundsAR - imageAR) < 0.17) {
//            zoomScale = MAX(xScale, yScale);
//            // Ensure we don't zoom in or out too far, just in case
////            zoomScale = MIN(MAX(self.minimumZoomScale, zoomScale), self.maximumZoomScale);
//            if (_photo.isVideo) {
//                zoomScale = MIN(MAX(self.minimumZoomScale, zoomScale), self.maximumZoomScale);
//            } else {
//                zoomScale = self.minimumZoomScale;
//            }
//        }
//    }
//    return zoomScale;
//}

- (void)setMaxMinZoomScalesForCurrentBounds {
    
    // Bail if no image
    if (_photoImageView.image == nil) return;
    
    
    // Sizes
    CGSize boundsSize = self.bounds.size;
    CGSize imageSize = _photoImageView.image.size;

    CGFloat maxScale = 1;
    
    
    CGFloat imgHeight = boundsSize.width / imageSize.width * imageSize.height;
    CGFloat w = boundsSize.width;
    CGFloat h = imgHeight;
    if (w < h) {
        maxScale = boundsSize.width * 2.5f / w;
    } else {
        maxScale = boundsSize.height * 2.5f / h;
    }
    
    self.maximumZoomScale = maxScale;
    
    
    _photoImageView.frame = CGRectMake(0, 0, w, h);
    if (h < boundsSize.height) {
        _photoImageView.center = CGPointMake(boundsSize.width / 2, boundsSize.height / 2);
        self.contentSize = self.bounds.size;
    }else {
        self.contentSize = _photoImageView.frame.size;
    }
    
    
    self.zoomScale = 1;

}

#pragma mark - Layout

- (void)layoutSubviews {
    
    // Update tap view frame
    _tapView.frame = self.bounds;
    
    // Position indicators (centre does not seem to work!)
    if (!_loadingIndicator.hidden)
        _loadingIndicator.frame = CGRectMake(floorf((self.bounds.size.width - _loadingIndicator.frame.size.width) / 2.),
                                         floorf((self.bounds.size.height - _loadingIndicator.frame.size.height) / 2),
                                         _loadingIndicator.frame.size.width,
                                         _loadingIndicator.frame.size.height);
//    if (_loadingError)
//        _loadingError.frame = CGRectMake(floorf((self.bounds.size.width - _loadingError.frame.size.width) / 2.), floorf((self.bounds.size.height - _loadingError.frame.size.height) / 2), _loadingError.frame.size.width, _loadingError.frame.size.height);

    // Super
    [super layoutSubviews];
    
    // Center the image as it becomes smaller than the size of the screen
    CGSize boundsSize = self.bounds.size;
    CGRect frameToCenter = _photoImageView.frame;
    
    // Horizontally
    if (frameToCenter.size.width < boundsSize.width) {
        frameToCenter.origin.x = floorf((boundsSize.width - frameToCenter.size.width) / 2.0);
    } else {
        frameToCenter.origin.x = 0;
    }
    
    // Vertically
    if (frameToCenter.size.height < boundsSize.height) {
        frameToCenter.origin.y = floorf((boundsSize.height - frameToCenter.size.height) / 2.0);
    } else {
        frameToCenter.origin.y = 0;
    }
    
    // Center
    if (!CGRectEqualToRect(_photoImageView.frame, frameToCenter))
        _photoImageView.frame = frameToCenter;
    
}

#pragma mark - UIScrollViewDelegate

- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
    return _photoImageView;
}

- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
//    [_photoBrowser cancelControlHiding];
}

- (void)scrollViewWillBeginZooming:(UIScrollView *)scrollView withView:(UIView *)view {
    self.scrollEnabled = YES; // reset
//    [_photoBrowser cancelControlHiding];
}

- (void)scrollViewDidZoom:(UIScrollView *)scrollView {
    CGFloat offsetX = (scrollView.frame.size.width > scrollView.contentSize.width) ? (scrollView.frame.size.width - scrollView.contentSize.width) * 0.5 : 0.0;
    CGFloat offsetY = (scrollView.frame.size.height > scrollView.contentSize.height) ? (scrollView.frame.size.height - scrollView.contentSize.height) * 0.5 : 0.0;
    _photoImageView.center = CGPointMake(scrollView.contentSize.width * 0.5 + offsetX, scrollView.contentSize.height * 0.5 + offsetY);
}

#pragma mark - Tap Detection

- (void)handleSingleTap:(CGPoint)touchPoint {
    [_photoBrowser performSelector:@selector(toggleControls) withObject:nil afterDelay:0.2];
}

- (void)handleDoubleTap:(CGPoint)touchPoint {
    
    // Dont double tap to zoom if showing a video
    if ([self displayingVideo]) {
        return;
    }
    
    // Cancel any single tap handling
    [NSObject cancelPreviousPerformRequestsWithTarget:_photoBrowser];
    
    // Zoom
    if (self.zoomScale > 1) {
        // Zoom out
        [self setZoomScale:self.minimumZoomScale animated:YES];
        
    } else {
        
        // Zoom in to twice the size
        CGFloat newZoomScale = self.maximumZoomScale;
        if (CGRectGetWidth(_photoImageView.bounds) < CGRectGetWidth(self.frame)) {
            if (CGRectGetWidth(self.frame) / CGRectGetWidth(_photoImageView.frame) < newZoomScale) {
                newZoomScale = CGRectGetWidth(self.frame) / CGRectGetWidth(_photoImageView.frame);
            }
        } else if (CGRectGetHeight(_photoImageView.frame) < CGRectGetHeight(self.frame)) {
            if (CGRectGetHeight(self.frame) / CGRectGetHeight(_photoImageView.frame) < newZoomScale) {
                newZoomScale = CGRectGetHeight(self.frame) / CGRectGetHeight(_photoImageView.frame);
            }
        }
        
        
        CGFloat width = self.frame.size.width;
        CGFloat height = self.frame.size.height;
        CGFloat xsize = width / newZoomScale;
        CGFloat ysize = height / newZoomScale;
        [self zoomToRect:CGRectMake(touchPoint.x - xsize/2, touchPoint.y - ysize/2, xsize, ysize) animated:YES];
    }
}

// Image View
- (void)imageView:(UIImageView *)imageView singleTapDetected:(UITouch *)touch {
    [self handleSingleTap:[touch locationInView:imageView]];
}
- (void)imageView:(UIImageView *)imageView doubleTapDetected:(UITouch *)touch {
    [self handleDoubleTap:[touch locationInView:imageView]];
}

// Background View
- (void)view:(UIView *)view singleTapDetected:(UITouch *)touch {
    // Translate touch location to image view location
    CGFloat touchX = [touch locationInView:view].x;
    CGFloat touchY = [touch locationInView:view].y;
    touchX *= 1/self.zoomScale;
    touchY *= 1/self.zoomScale;
    touchX += self.contentOffset.x;
    touchY += self.contentOffset.y;
    [self handleSingleTap:CGPointMake(touchX, touchY)];
}
- (void)view:(UIView *)view doubleTapDetected:(UITouch *)touch {
    // Translate touch location to image view location
    CGFloat touchX = [touch locationInView:view].x;
    CGFloat touchY = [touch locationInView:view].y;
    touchX *= 1/self.zoomScale;
    touchY *= 1/self.zoomScale;
    touchX += self.contentOffset.x;
    touchY += self.contentOffset.y;
    [self handleDoubleTap:CGPointMake(touchX, touchY)];
}

#pragma mark - getter or setter
- (UIImageView *)imageView {
    return _photoImageView;
}

@end
